﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using MockingBird.Common.Infrastructure.DependencyResolution;


namespace MockingBird.Simulator.Framework
{
    using MockingBird.Common.Infrastructure.Configuration;
    using MockingBird.Simulator.Framework.Configuration;

    using Interfaces;
    using System.Diagnostics;
    using System.Threading;

    public class ConfigFileBasedHandlerResolver : IHandlerResolver
    {
        private SystemConfigurationManager sysConfigManager;
        private HandlerMapInfo handlerMapInfo;
        private HandlerRegistrationInfo handlerRegistrationInfo;

        public ConfigFileBasedHandlerResolver()
        {
        }

        public ConfigFileBasedHandlerResolver(HandlerMapInfo handlerMapData, HandlerRegistrationInfo handlerRegData, SystemConfigurationManager systemConfigurationManager)
        {
            Debug.WriteLine(string.Format("ConfigFileBasedHandlerResolver.ctor on thread ID: {0}", Thread.CurrentThread.ManagedThreadId));

            this.handlerMapInfo = handlerMapData;
            this.handlerRegistrationInfo = handlerRegData;
            this.sysConfigManager = systemConfigurationManager;
        }

        public void Load()
        {
            this.InitializeSystemConfiguration();

            this.LoadDataFromSystemConfiguration();

            this.ValidateConfiguration();
        }

        private void InitializeSystemConfiguration()
        {
            if(this.sysConfigManager == null)
            {
                sysConfigManager = DependencyResolver.DefaultContainer.Resolve<SystemConfigurationManager>();
            }

        }


        
        private void LoadDataFromSystemConfiguration()
        {
            if ((this.handlerMapInfo == null) || (this.handlerMapInfo.IsEmpty))
            {
                this.handlerMapInfo = new HandlerMapInfo();
                string xml = this.sysConfigManager.GetSectionXml("HandlerMap");
                this.handlerMapInfo.LoadInfoFromXml(xml);
            }
            if ((this.handlerRegistrationInfo == null) || (this.handlerRegistrationInfo.IsEmpty))
            {
                this.handlerRegistrationInfo = new HandlerRegistrationInfo();
                string xml = this.sysConfigManager.GetSectionXml("HandlerRegistration");
                this.handlerRegistrationInfo.LoadInfoFromXml(xml);
            }
        }

        private void ValidateConfiguration()
        {
            //this may still be null
            if ((this.handlerMapInfo == null) || (this.handlerMapInfo.IsEmpty))
            {
                throw new InvalidDataException("HandlerMapInfo is Empty Or Null.Cannot proceed");
            }

            if ((this.handlerRegistrationInfo == null) || (this.handlerRegistrationInfo.IsEmpty))
            {
                throw new InvalidDataException("HandlerRegistrationInfo is Empty Or Null.Cannot proceed");
            }
        }
        public string GetHandlerNameForEndpoint(string endpoint)
        {
            string handlerName = handlerMapInfo.GetHandlerNameForEndpoint(endpoint);
            //if there is no handler for the endpoint then throw an exception
            if (String.IsNullOrEmpty(handlerName))
            {

                throw new ConfigurationErrorsException("Request Handler not available for endpoint : " + endpoint);
            }

            return handlerName;

        }

        public Type GetHandlerType(string handlerName)
        {

            //Get the handler type name from the registration info structure and throw an exception 
            //if we cant find anything registered
            string handlerFullTypeName = handlerRegistrationInfo.GetHandlerTypeName(handlerName);
            
            if(String.IsNullOrEmpty(handlerFullTypeName))
                throw new ConfigurationErrorsException("could not find a registered type for the specified handler name :" + handlerName);

            return CreateAndReturnType(handlerFullTypeName);
 
        }

        private Type CreateAndReturnType(string handlerFullTypeName)
        {
            //Now parse the type name to get the assembly name and the short type name
            string handlerAssemblyName = handlerFullTypeName.Split(",".ToCharArray())[1];
            string handlerShortTypeName = handlerFullTypeName.Split(",".ToCharArray())[0];

            //Create an appropriate type from the assembly and return it
            var handlerAsssembly = Assembly.Load(handlerAssemblyName);
            Type handlerType = handlerAsssembly.GetType(handlerShortTypeName);

            return handlerType;
            
        }


    }
}
